package org.netty.framework.httpserver;

import org.netty.framework.core.NettyServer;
import org.netty.framework.core.Protocol;
import org.netty.framework.core.concurrent.ThreadPoolExecutorFactory;
import org.netty.framework.core.config.NettyServerConfig;
import org.netty.framework.httpserver.handle.HttpServerInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * http server服务启动
 * 
 * @author chenfanglin
 * @date 2018年9月20日下午2:31:27
 *
 */
public class HttpServer implements NettyServer {

	private static final Logger logger = LoggerFactory.getLogger(HttpServer.class);

	/**
	 * boss线程池,接收客户端请求
	 */
	private EventLoopGroup bossGroup;

	/**
	 * worker线程池,处理IO读写任务
	 */
	private EventLoopGroup workerGroup;

	/**
	 * netty日志记录的handle
	 */
	private LoggingHandler loggingHandler;

	/**
	 * 定义pipeline,将worker线程处理的channelhandle放到责任链中.
	 */
	private HttpServerInitializer httpServerInitializer;

	private HttpServer() {
		// 默认是CPU核心数的两倍
		bossGroup = new NioEventLoopGroup();
		workerGroup = new NioEventLoopGroup();
		loggingHandler = new LoggingHandler(LogLevel.INFO);
		httpServerInitializer = new HttpServerInitializer();
		/**
		 * 初始化业务线程池
		 */
		ThreadPoolExecutorFactory.createThreadPoolExecutor(this);
	}

	@Override
	public void start() {
		long start = System.currentTimeMillis();
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(loggingHandler)
				.childHandler(httpServerInitializer);
		NettyServerConfig.setTcpChannelOptions(serverBootstrap);
		try {
			int port = NettyServerConfig.getHttpServerPort();
			// 绑定端口,接收客户端的连接,线程会一致阻塞在这里
			ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
			channelFuture.addListener(new ChannelFutureListener() {
				@Override
				public void operationComplete(ChannelFuture future) throws Exception {
					logger.info("http server start successful,port={},use time={}ms", port,
							(System.currentTimeMillis() - start));
				}
			});
			// server socket close
			channelFuture.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			stop();
		}
	}

	@Override
	public void stop() {
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
	}

	@Override
	public Protocol getProtocol() {
		return Protocol.HTTP;
	}

}
